﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections.Generic;
using System.Linq;

namespace DonetArxLib
{
    internal class SpaceInfoAnalysis
    {
        static readonly string HOUSE_LAYER_NAME = "户型轮廓";
        static readonly string ROOM_LAYER_NAME = "房间轮廓";

        private List<SpaceNameInfo> _houses = new List<SpaceNameInfo>();
        private List<SpaceNameInfo> _rooms = new List<SpaceNameInfo>();

        private List<TextInfo> _houseText = new List<TextInfo>();
        private List<TextInfo> _roomText = new List<TextInfo>();

        public void DoIt()
        {
            CollectEntityInfo();
            if (_rooms.Count == 0 || _houses.Count == 0)
            {
                var ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage("\nNo room or house found!");
            }

            PickName();
            PrintInfo();
        }

        private void PrintInfo()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            ed.WriteMessage("\nHouse Info:");
            ed.WriteMessage("\n-----------------------------------");
            ed.WriteMessage("\n| House Name       | Area         |");
            ed.WriteMessage("\n-----------------------------------");
            foreach (var house in _houses)
            {
                ed.WriteMessage($"\n| {house.Name,-15} | {house.Area.ToString("F0"),-12} |");
            }
            ed.WriteMessage("\n-----------------------------------");

            ed.WriteMessage("\nRoom Info:");
            ed.WriteMessage("\n-----------------------------------");
            ed.WriteMessage("\n| Room Name        | Area         |");
            ed.WriteMessage("\n-----------------------------------");
            foreach (var room in _rooms)
            {
                ed.WriteMessage($"\n| {room.Name,-15} | {room.Area.ToString("F0"),-12} |");
            }
            ed.WriteMessage("\n-----------------------------------");
        }

        private void CollectEntityInfo()
        {
            var db = HostApplicationServices.WorkingDatabase;
            if (db == null)
                throw new InvalidOperationException("no database!");

            using (var trans = db.TransactionManager.StartTransaction())
            {
                try
                {
                    UtilFunc.IterateEntitiesInModelSpace(entID =>
                    {
                        var obj = UtilFunc.GetObject(trans, entID, OpenMode.ForRead) as Entity;
                        if (obj == null)
                            return true;

                        if (obj is Polyline pl && pl.Closed && (pl.Layer == HOUSE_LAYER_NAME || pl.Layer == ROOM_LAYER_NAME))
                        {
                            var info = new SpaceNameInfo
                            {
                                Area = pl.Area,
                                EntityId = entID,
                                Extents = pl.GeometricExtents
                            };

                            if (pl.Layer == HOUSE_LAYER_NAME)
                                _houses.Add(info);
                            else
                                _rooms.Add(info);
                        }
                        else if (obj is DBText txt || obj is MText mt)
                        {
                            var text = obj is DBText ? ((DBText)obj).TextString : ((MText)obj).Text;
                            var ext = obj.GeometricExtents;
                            var info = new TextInfo
                            {
                                Text = text,
                                Extents = ext,
                                EntityId = entID
                            };
                            if (obj.Layer == HOUSE_LAYER_NAME)
                                _houseText.Add(info);
                            else if (obj.Layer == ROOM_LAYER_NAME)
                                _roomText.Add(info);
                        }

                        return true;
                    }, trans, db);
                }
                finally
                {
                    trans.Abort();
                }
            }
        }

        private void PickName()
        {
            foreach (var room in _rooms)
            {
                room.Name = _roomText.FirstOrDefault(text => IsTextInPolyline(text.Extents, room.Extents))?.Text ?? room.Name;
            }
            foreach (var house in _houses)
            {
                house.Name = _houseText.FirstOrDefault(text => IsTextInPolyline(text.Extents, house.Extents))?.Text ?? house.Name;
            }
        }

        private bool IsTextInPolyline(Extents3d extText, Extents3d extPline)
        {
            return extPline.MaxPoint.X > extText.MaxPoint.X && extPline.MinPoint.X < extText.MinPoint.X &&
                   extPline.MaxPoint.Y > extText.MaxPoint.Y && extPline.MinPoint.Y < extText.MinPoint.Y;
        }
    }

    class SpaceNameInfo
    {
        public string Name { get; set; } = "";
        public double Area { get; set; } = 0.0;
        public ObjectId EntityId { get; set; } = ObjectId.Null;
        public Extents3d Extents { get; set; }
    }

    class TextInfo
    {
        public string Text { get; set; } = "";
        public Extents3d Extents { get; set; }
        public ObjectId EntityId { get; set; } = ObjectId.Null;
    }
}
